#ifndef __ARCH_MP_H
#define __ARCH_MP_H

#include <arch/config.h>

#ifdef ENABLE_SMP

#include <lib/type.h>
#include <arch/page.h>
#include <arch/tss.h>
#include <arch/cpu.h>

// system maximum number of cpus
#define PROCESSOR_MAX CPU_NUM_MAX

// AP StartUP IPI vector
#define STARTUP_IPI_VECTOR ((AP_STARTUP_ADDR) >> 12)
#define MP_EXCAPPOINT_VECTOR 0x71

// AP start pyaddr
#define AP_STARTUP_ADDR 0x7000
#define AP_STARTUP_VADDR (PAGE_HIGH_BASE + AP_STARTUP_ADDR)

// AP stack size
#define AP_STACK_SIZE 128

//APIC table size
#define APIC_TABLE_SIZE 0x400

typedef void (*mp_appoint_func_t)();
typedef struct apinit apinit_t;

// ap init data block
#pragma pack(push, 1)
typedef struct apinit
{
    uint32_t stack;
    uint32_t pagebase;
    uint32_t tss;
    uint16_t idt_limit;
    uint32_t idt_vbase;
    uint16_t gdt_limit;
    uint32_t gdt_vbase;
} apinit_data_t;
#pragma pack(pop)

typedef struct
{
    uint8_t id;               // process id
    uint8_t enalbe;           // process is enalbe
    uint8_t APIC_ID;          // APIC ID
    uint8_t ACPI_ID;          // ACPI process ID
    uint8_t family;           // CPU family
    uint8_t init;             // init flags
    uint32_t ticks;           // cpu run ticks
    uint32_t frequery;        // cpu frequery
    uint32_t max_frequery;    // cpu frequery max
    uint32_t actual_frequery; // current frequery
    uint32_t bus_frequery;    // cpu bus frequery
    uint32_t timer_frequery;  // timer freqery
    apinit_data_t init_data;  // init data
} processor_info_t;

extern processor_info_t processor_info[PROCESSOR_MAX];
extern apinit_data_t apinit_data;
extern uint8_t bsp_id;
extern uint8_t mpinit;

// ap init entry point
extern void __bootap_enter();
extern void __bootap_end();

void MpInit();
void MpEnd(processor_info_t *proc);
void MpStart(uint8_t apic_id);
void MpStartInit();
void MpGetAllCpu();
void MpStartAp();
processor_info_t *MpGetProcessor();
processor_info_t *MpGetBspProcessor();
void MpExecAppoint(uint8_t cpu, void *func);
processor_info_t *MpGetProcessorById(uint8_t cpu);

#define CurProcessor MpGetProcessor()
#define CurProcessorID MpGetProcessor()->APIC_ID
#define CurProcessorStack MpGetProcessor()->stack
#define CurProcessorPage MpGetProcessor()->pagebase
#define CurTimerFrequery MpGetProcessor()->timer_frequery
#define CurBusFrequery MpGetProcessor()->bus_frequery
#define CurFrequery MpGetProcessor()->frequery
#define CurMaxFrequery MpGetProcessor()->max_frequery
#define CurActualFrequery MpGetProcessor()->actual_frequery
#endif

#endif